<?php

/**
 * 拼多多小巨人对接菜鸟专用接口
 * @author chenshubo
 */
namespace App\Service\VendorClient\ShopCaiNiao;
use App\Service\BaseService;
use App\Service\Code\Normal;
use Service\AppService\IdService;
use App\Service\TaskServer\TaskWorker;
use App\Service\AppService\SystemCacheConfigService;
use App\Model\PssModel\ServiceConfig;
use function GuzzleHttp\json_encode;

class ShopPddOrderSendCaiNiaoSupplierApiClient extends BaseService
{
    protected $clientConfig;
    
    public function __construct( $apiBody = [] )
    {
        $this->clientConfig = $apiBody;
    }
    
    /**
     * 创建订单
     */
    public function createOrder( $param = [] )
    {
        $orderInfo      = $param['supplierOrder'];
        $orderItem      = $param['orderGoods'];
        $order          = $param['order'];
        $binfo          = $param['binfo'];
        $PddExtends     = $param['PddExtends'] ?? [] ;
        //支付流水号
        $pay_sn         = $order['paySerial'] ?? $orderInfo['pay_sn'];
        //运费
        $deliver_money  = bcmul($orderInfo['deliver_money'], 100);
        //支付时间
        $pay_time       = date('Y-m-d H:i:s',$orderInfo['pay_time']);
        $order_sn       = $orderInfo['supplier_dsn'];
        
        //组装商品数据列表
        $goodsList  = [];
        $goodsTotalMoney = $ConsumptionTax = $CustomsTax = $VAT = $TotalTax = $Insurance = $Coupon = 0;
        $firstOrderItem = current($orderItem);
        foreach ($orderItem as $item )
        {
            $tax_rate           = bcadd('1', (string)$item['tax_rate'],4);
            $price              = $item['price'];
            $spec_num           = $item['spec_num'];
            $quantity           = $item['quantity'];
        
            //不含税价格
            $goodsPrice         = bcdiv((string)$price, (string)$tax_rate,3);
            $goodsPrice         = ceil(bcmul((string)$goodsPrice,(string)100))/100;
            $buyNum             = $spec_num * $quantity;
            $goodsTotalPrice    = bcmul((string)$goodsPrice,(string)$quantity,2);
            $goodsTotalPrice    = bcmul((string)$goodsTotalPrice,(string)100);
            //商品关税当前币种最小单位（分）
            $goodsCustomsTax      = bcsub((string)$price,(string)$goodsPrice,2);
            $goodsCustomsTax      = bcmul((string)$goodsCustomsTax,(string)100);
            //商品消费税
            $goodsConsumptionTax  = 0;
            //商品增值税
            $goodsVAT = 0 ;
            //商品综合税,当前币种最小单位（分）
            $goodsCustomsTax      = bcmul((string)$goodsCustomsTax,(string)$quantity);
            $goodsList[] = [
                'itemId'                => $item['supplier_skucode'],
                'goodsQuantity'         => $buyNum,
                'goodsTotalPrice'       => (int)$goodsTotalPrice,//该明细行商品总价（优惠前）当前币种最小单位（分）(商品完税价)
                'goodsTotalActualPrice' => (int)$goodsTotalPrice,//该明细行商品总价（优惠后）当前币种最小单位（分）（商品实付金额）
                'goodsCustomsTax'       => (int)$goodsCustomsTax,//商品关税
                'goodsConsumptionTax'   => (int)$goodsConsumptionTax,//商品消费税
                'goodsVAT'              => (int)$goodsVAT,//商品增值税
                'goodsTotalTax'         => (int)$goodsCustomsTax,//商品综合税,当前币种最小单位（分）
                'hscode'                => $item['declare_hscode'],//hscode
            ];
            $goodsTotalMoney    = bcadd((string)$goodsTotalMoney,(string)$goodsTotalPrice);
            $ConsumptionTax     = bcadd((string)$ConsumptionTax,(string)$goodsConsumptionTax);
            $VAT                = bcadd((string)$VAT,(string)$goodsVAT);
            $CustomsTax         = bcadd((string)$CustomsTax,(string)$goodsCustomsTax);
            $TotalTax           = bcadd((string)$TotalTax,(string)$goodsCustomsTax);
        }
        
        //处理截位
        $pay_sn             = mb_substr($pay_sn,0,32,"utf-8");
        $buyerName          = mb_substr($orderInfo['buyer_realname'],0,64,"utf-8");
        $receive_address    = mb_substr($orderInfo['receive_address'],0,512,"utf-8");
        
        //收货地址信息
        $receiverContact = [
            'contactName'   => $orderInfo['receive_name'],
            'zipCode'       => '000000',
            'address'       => $receive_address,
            'province'      => $orderInfo['province'],
            'city'          => $orderInfo['city'],
            'district'      => $orderInfo['district'],
            'mobilePhone'   => mb_substr($orderInfo['recveive_phone'],0,32,"utf-8"),
        ];
        
        $wareHouseParameters = @json_decode($firstOrderItem['supplier_store_parameters'],true);
        if( empty($wareHouseParameters) ) {
            return Normal::returnCode(Normal::FAIL,"菜鸟供应商仓库设置参数不能为空");
        }
        
        //检查仓库对应的配置是否正确
        $wareHouseParameters = array_column($wareHouseParameters,'parameterValue','parameterKey');
        $checkConfig = [
            'appSecret',
            'storeCode',
            'ownerUserId',
            'cpCode',
            'senderContactContactName',
            'senderContactZipCode',
            'senderContactAddress',
            'senderContactProvince',
            'senderContactCity',
            'senderContactDistrict',
            'senderContactMobilePhone',
            'refunderContactName',
            'refunderContactZipCode',
            'refunderContactAddress',
            'refunderContactProvince',
            'refunderContactCity',
            'refunderContactDistrict',
            'refunderContactMobilePhone',
        ];
        $res = SystemCacheConfigService::instance()->checkAllowApiColumnsByFields($wareHouseParameters,$checkConfig);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        
        //发货地址信息
        $senderContact = [
            'contactName'   => $wareHouseParameters['senderContactContactName'],
            'zipCode'       => $wareHouseParameters['senderContactZipCode'],
            'address'       => $wareHouseParameters['senderContactAddress'],
            'country'       => 'CN',
            'province'      => $wareHouseParameters['senderContactProvince'],
            'city'          => $wareHouseParameters['senderContactCity'],
            'district'      => $wareHouseParameters['senderContactDistrict'],
            'mobilePhone'   => $wareHouseParameters['senderContactMobilePhone'],
        ];
        
        //退货地址信息
        $refunderContact = [
            'contactName'   => $wareHouseParameters['refunderContactName'],
            'zipCode'       => $wareHouseParameters['refunderContactZipCode'],
            'address'       => $wareHouseParameters['refunderContactAddress'],
            'country'       => 'CN',
            'province'      => $wareHouseParameters['refunderContactProvince'],
            'city'          => $wareHouseParameters['refunderContactCity'],
            'district'      => $wareHouseParameters['refunderContactDistrict'],
            'mobilePhone'   => $wareHouseParameters['refunderContactMobilePhone'],
        ];
        
        //订单完税价，当前币种最小单位（分）注意：订单完税价＝订单商品｜优惠前｜价格总和＋运费＋保费
        $DutiablePrice  = bcadd((string)$goodsTotalMoney,(string)$deliver_money);
        $DutiablePrice  = bcadd((string)$DutiablePrice, (string)$Insurance);
        
        //实际支付金额 = $DutiablePrice + $TotalTax - $Coupon
        $Actualpayment  = bcadd($DutiablePrice, $TotalTax);
        
        //订单买家实付金额,当前币种最小单位（分）
        $real_total_money = $orderInfo['real_total_money'];
        $real_total_money = bcmul((string)$real_total_money,(string)100);
        
        //优惠金额度
        $Coupon         = bcsub((string)$Actualpayment,(string)$real_total_money);
        
        //支付电商平台
        $apply_extends  = @json_decode($orderInfo['apply_extends'],true);
        $waybill_info   = isset($order['waybill_info']) ? $order['waybill_info'] : ( $apply_extends['waybill_info'] ?? [] );
        $res = $this->checkWayBillInfo($waybill_info);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        
        $enterpriseNum  = $apply_extends['enterpriseNum']??'';
        $enterpriseNum  = $order['enterpriseNum'] ? $order['enterpriseNum'] : $enterpriseNum ;
        
        //获取电商平台映射配置
        $channel_value = ServiceConfig::instance()->getConfigByEventsValue('cainiao', ServiceConfig::TYPE_CHANNEL, $enterpriseNum);
        if( empty($channel_value) ) {
            return Normal::returnCode(Normal::FAIL,"电商平台编码：【{$enterpriseNum}】未映射，请联系管理员处理");
        }
        
        //获取支付方式配置
        $payCommanyCode = $apply_extends['payCommanyCode']??'';
        $PayCompanyCode = $order['payCommanyCode'] ? $order['payCommanyCode'] : $payCommanyCode ;
        $pay_value = ServiceConfig::instance()->getConfigByEventsValue('cainiao', ServiceConfig::TYPE_PAY, $PayCompanyCode);
        if( empty($pay_value) ) {
            return Normal::returnCode(Normal::FAIL,"支付公司编码：【{$PayCompanyCode}】未映射，请联系管理员处理");
        }
        
        if( empty($PddExtends['wp_code']) ) {
            return Normal::returnCode(Normal::FAIL,"拼多多授权参数wp_code物流公司编码未配置");
        }
        
        if( empty($waybill_info['print_code']) ) {
            return Normal::returnCode(Normal::FAIL,"面单参数print_code获取失败");
        }
		
        if( $waybill_info['print_code'] != Normal::SUC ) {
            return Normal::returnCode(Normal::FAIL,"拼多多面单信息获取失败【{$waybill_info['print_code']}】");
        }
        
        unset($waybill_info['print_code']);
        
        //获取快递方式配置
        $wayCode = ServiceConfig::instance()->getConfigByEventsValue('cainiao', ServiceConfig::TYPE_BILL_WAY, $PddExtends['wp_code']);
        if( empty($wayCode) ) {
            return Normal::returnCode(Normal::FAIL,"菜鸟快递方式未：【{$PddExtends['wp_code']}】未映射，请联系管理员处理");
        }
        
        //创建订单数据
        $data = [
            'externalOrderId'       => $order_sn,
            'userId'                => $wareHouseParameters['ownerUserId'],
            'businessUnitId'        => $wareHouseParameters['businessUnitId'],
            'shopNick'              => $binfo['name'],
            'orderSource'           => $channel_value,
            'orderType'             => '01',
            'storeCode'             => $wareHouseParameters['storeCode'],//保税仓／海外仓仓库编码
            'postFee'               => (int)$deliver_money,//不包含在商品价格中的运杂费。当前币种最小单位（分）
            'currency'              => 'CNY',//币制
            'buyerName'             => $buyerName,
            'buyerId'               => $binfo['bid'],
            'buyerIDType'           => 1,//1-身份证,2-其它。限定为身份证，填写“1”。如果支付宝实名制验证的证件类型不是身份证，则提示证件类型不是身份证，不允许申报。
            'buyerIDNo'             => $orderInfo['buyer_idcard'],//支付人人的身份证件号码，判断是否是15位或者18位
            'payType'               => $pay_value,//支付企业名称，支付宝支付 01;微信支付 02;
            'payOrderId'            => $pay_sn,//支付企业唯一的支付流水号。
            'buyTime'               => date("Y-m-d H:i:s",$orderInfo['cd']),//下单时间yyyy-MM-dd HH:mm:ss
            'payTime'               => date("Y-m-d H:i:s",time()),//支付时间yyyy-MM-dd HH:mm:ss
            'message'               => $orderInfo['order_remark'],//客户留言
            'DutiablePrice'         => (int)$DutiablePrice,//订单完税价，当前币种最小单位（分）注意：订单完税价＝订单商品｜优惠前｜价格总和＋运费＋保费
            'CustomsTax'            => (int)$CustomsTax,//订单关税，当前币种最小单位（分）
            'ConsumptionTax'        => (int)$ConsumptionTax,//订单消费税最小单位（分）
            'VAT'                   => (int)$VAT,//订单消费税,当前币种最小单位（分）
            'TotalTax'              => (int)$TotalTax,//订单增值税,当前币种最小单位（分）
            'Insurance'             => (int)$Insurance,//订单保险费,当前币种最小单位（分）
            'Coupon'                => (int)$Coupon,//订单优惠,当前币种最小单位（分）
            'Actualpayment'         => (int)$real_total_money,//订单买家实付金额,当前币种最小单位（分）
            'goodsList'             => $goodsList,
            'receiverContact'       => $receiverContact,
            'senderContact'         => $senderContact,
            'refunderContact'       => $refunderContact,
            'extendsField'          => json_encode([
                'is_CNQG'           => 1,
                'extApplyWaybill'   => 'Y',
                'cpCode'            => $wayCode,
                'mailNo'            => $waybill_info['waybill_code'],
                'printData'         => $waybill_info['print_data'],
            ])
        ];
        $requestParam = [
            'method'    => 'orderCreate',
            'data'      => $data,
            'config'    => $wareHouseParameters,
            'format'    => 'json'
        ];
        $res = $this->execute($requestParam);
        if ($res['code'] == Normal::SUC ) {
            return Normal::returnCode(Normal::SUC,"订单推送成功",[
                'thirdpart_order_sn' => $res['data']['lgorderCode']
            ]);
        }
        return $res;
    }
    
    /**
     * 校验面单参数
     * @param array $waybill_info
     * @return mixed
     */
    public function checkWayBillInfo( $waybill_info = [] )
    {
        if( empty($waybill_info) ) {
            return Normal::returnCode(Normal::FAIL,"当前拼多多面单信息不能为空");
        }
        
        if( empty($waybill_info['print_data']) ) {
            return Normal::returnCode(Normal::FAIL,"拼多多小巨人渠道电子面单信息print_data参数缺失");
        }
        
        if( empty($waybill_info['waybill_code']) ) {
            return Normal::returnCode(Normal::FAIL,"拼多多小巨人渠道电子面单信息waybill_code参数缺失");
        }
        
        if( empty($waybill_info['wp_code']) ) {
            return Normal::returnCode(Normal::FAIL,"拼多多小巨人渠道电子面单信息wp_code参数缺失");
        }
        
        return Normal::returnCode(Normal::SUC,"校验通过");
    }
    
    /**
     * 取消订单
     */
    public function cancelOrder( $params = [] )
    {
        if( empty($params['supplierOrder']) ) {
            return Normal::returnCode(Normal::FAIL,"except param supplierOrder");
        }
        
        if( empty($params['orderGoods']) ) {
            return Normal::returnCode(Normal::FAIL,"except param orderGoods");
        }
        
        $firstOrderItem = current($params['orderGoods']);
        $wareHouseParameters = @json_decode($firstOrderItem['supplier_store_parameters'],true);
        if( empty($wareHouseParameters) ) {
            return Normal::returnCode(Normal::FAIL,"菜鸟供应商仓库设置参数不能为空");
        }
        
        $checkConfig = [
            'ownerUserId',
        ];
        $wareHouseParameters = array_column($wareHouseParameters,'parameterValue','parameterKey');
        $res = SystemCacheConfigService::instance()->checkAllowApiColumnsByFields($wareHouseParameters,$checkConfig);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        
        $data = [
            'userId'        => $wareHouseParameters['ownerUserId'],
            'lgOrderCode'   => $params['supplierOrder']['thirdpart_order_sn']
        ];
        $requestParam = [
            'method'    => 'orderCancel',
            'data'      => $data,
            'config'    => $wareHouseParameters,
            'format'    => 'json'
        ];
        return $this->execute($requestParam);
    }
    
    /**
     * 关务申报单报文查询(非淘)CUSTOMS_DECLARE_ORDER_MESSAGE_QUERY
     * @param array $param
     */
    public function queryOrderDeclare( $param = [] )
    {
        $supplierOrder  = $param['supplierOrder'];
        $orderGoods     = $param['orderGoods'];
        $supplier       = $param['supplier'];
        $firstOrderItem = current($param['orderGoods']);
        $wareHouseParameters = @json_decode($firstOrderItem['supplier_store_parameters'],true);
        if( empty($wareHouseParameters) ) {
            return Normal::returnCode(Normal::FAIL,"菜鸟供应商仓库设置参数不能为空");
        }
        $wareHouseParameters = array_column($wareHouseParameters,'parameterValue','parameterKey');
        $data = [
            'logisticsOrderNo'   => $supplierOrder['thirdpart_order_sn']
        ];
        $requestParam = [
            'return'        => true,
            'uid'           => $supplierOrder['order_sn'],
            'company_code'  => $supplier['company_code'],
            'method'        => 'queryOrderDeclare',
            'data'          => $data,
            'config'        => $wareHouseParameters,
            'format'        => 'xml'
        ];
        return $this->execute($requestParam);
    }
    
    /**
     * CP传揽收节点给菜鸟，用于结算物流费用：CAINIAO_GLOBAL_LASTMILE_HOIN_CALLBACK
     */
    public function cpLogisticsCourier( $param = [] )
    {
        if( empty($param['supplierOrder']) ) {
            return Normal::returnCode(Normal::FAIL,"except param supplierOrder");
        }
        
        if( empty($param['orderGoods']) ) {
            return Normal::returnCode(Normal::FAIL,"except param orderGoods");
        }
        
        $orderInfo      = $param['supplierOrder'];
        $orderGoods     = $param['orderGoods'];
        $wareHouseParameters = current($orderGoods)['supplier_store_parameters'];
        $apply_extends  = @json_decode($orderInfo['apply_extends'],true);
        if( !isset($apply_extends['tracking_number']) ) {
            return Normal::returnCode(Normal::FAIL,"except param tracking_number");
        } 
        
        if( empty($apply_extends['waybill_info']) ) {
            return Normal::returnCode(Normal::FAIL,"except param waybill_info");
        }
        
        if( empty($apply_extends['waybill_info']['waybill_code']) ) {
            return Normal::returnCode(Normal::FAIL,"except param waybill_info.waybill_code");
        }
        
        if( empty($apply_extends['waybill_info']['wp_code']) ) {
            return Normal::returnCode(Normal::FAIL,"except param waybill_info.wp_code");
        }
        
        if( empty($orderInfo['thirdpart_order_sn']) ) {
            return Normal::returnCode(Normal::FAIL,"except param thirdpart_order_sn");
        }
        
        $checkConfig = [
            'cpCode',
        ];
        $wareHouseParameters = array_column($wareHouseParameters,'parameterValue','parameterKey');
        $res = SystemCacheConfigService::instance()->checkAllowApiColumnsByFields($wareHouseParameters,$checkConfig);
        if( $res['code'] != Normal::SUC ) {
            return $res;
        }
        
        $order_sn   = $orderInfo['order_sn'];
        $wp_code    = $apply_extends['waybill_info']['wp_code'];
        $data = [
            "logisticsOrderCode"    => $orderInfo['thirdpart_order_sn'],
            "trackingNumber"        => $apply_extends['tracking_number'],
            "waybillNumber"         => $apply_extends['waybill_info']['waybill_code'],
            "opTime"                => date("Y-m-d H:i:s"),
            "timeZone"              => "3",
            "transportType"         => 4,//水路运输(2)、铁路运输(3)、公路运输(4)、航空运输(5)、邮件运输(6)、其他运输(9) 运输类型，默认传4，公路运输
            "operator"              => $wp_code,
            "operatorContact"       => $wp_code,
            "opCode"                => "0",//0-代表揽收
            "parcel"                => [
                "bigBagID" => $order_sn,
            ],
        ];
        $requestParam = [
            'method'    => 'logisticsCourier',
            'data'      => $data,
            'config'    => $wareHouseParameters,
            'format'    => 'json'
        ];
        return $this->execute($requestParam);
    }
    
    /**
     * 获取sign参数
     */
    private function getSign( $param = [])
    {
       return base64_encode(md5(json_encode($param).$this->clientConfig['appSecret'], true));
    }
    
    public function arr_to_xml($data, $root = true)
    {
        $str = "";
        if ($root) {
            $str .= "<xml>";
        }
        foreach ($data as $key => $val) {
            $key= trim($key);
    
            if (is_array($val)) {
                $child = $this->arr_to_xml($val,false);
                $str.="<$key>$child</$key>";
            } else {
                $val= trim($val);
                $str.="<$key>$val</$key>";
            }
        }
        if ($root) {
            $str .= "</xml>";
        }
        return str_replace(PHP_EOL,"",$str);
    }
    
    /**
     * CURL请求
     * @param $params
     * @return mixed
     */
    public function execute( $param = [] )
    {
        $method     = $param['method'];
        $data       = $param['data'];
        if( empty($this->clientConfig['baseurl']) ) {
            return Normal::returnCode(Normal::FAIL,"当前仓库参数baseurl未配置");
        }
        
        if( empty($this->clientConfig[$method]) ) {
            return Normal::returnCode(Normal::FAIL,"当前仓库参数【{$method}】未配置");
        }
                
        $return        = $param['return'] ?? false;
        $uid           = $param['uid'] ?? false;
        $company_code  = $param['company_code'] ?? false;
        $config        = $param['config'];
        $data_digest = $this->getSign($data);
        if( !isset($this->clientConfig['api_route'][$method]) ) {
            return Normal::returnCode(Normal::FAIL,"方法配置不存在，请联系管理员和对处理！");
        }
        
        if( $param['format'] == 'json' ) {
            $logistic_provider_id = $config['cpCode'];
            $logistics_interface  = json_encode($param['data']);
        } else {
            $logistic_provider_id = $config['cpGwCode'];//关务应用appkey
            $logistics_interface  = $this->arr_to_xml($param['data']);
        }
        
        $param = [
            'msg_type'              => $this->clientConfig['api_route'][$method],
            'logistic_provider_id'  => $logistic_provider_id,
            'data_digest'           => $data_digest,
            'logistics_interface'   => $logistics_interface
        ];
        $url = $this->clientConfig['baseurl'];
        $form_data = [
            'tag'           => 'cainiao_'.$method,
            'uid'           => $uid ? $uid : IdService::instance()->getOtherID(),
            'company_code'  => $company_code,
            'url'           => $url,
            'data'          => $param,
            'method'        => 'post',
            'format'        => 'x-www-form-urlencoded',
            'header'        => [],
        ];
        
        if( $return ) {
            return Normal::returnCode(Normal::SUC,"获取成功",$form_data);
        }
        
        $parameter = [$form_data];
        $resTask    = TaskWorker::instance()->addTask($parameter);
        $resTask    = current($resTask);
        $res        = $resTask['response']['result'];
        $resHttp    = json_decode($res, true);
        if( empty($resHttp) ) {
            $resHttp = json_decode(json_encode(simplexml_load_string($res, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        }
        
        $errorMsg = $resHttp['errorMsg']??'请求失败';
        if( isset($resHttp['success']) && $resHttp['success'] == 'true' ) {
            return Normal::returnCode(Normal::SUC,"操作成功",$resHttp);
        }
        return Normal::returnCode(Normal::FAIL,$errorMsg);
    }
}